﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.IO;

/// <summary>
/// Summary description for TermIndexReader
/// </summary>
public class TermIndexReader
{
    struct OffsetLength
    {
        public int offset;
        public int length;
    }

    Dictionary<int, OffsetLength> termId2offset;
    int[] aiSentIdData;
    int iDataInMemorySizeByByte;
    StreamReader sr;
    BinaryReader br;
    private object privateObject = new object();
 
    public TermIndexReader()
    {
        termId2offset = new Dictionary<int, OffsetLength>();
    }

    public bool Open(string fileName, string dataFileName, double fPercentInMemory)
    {
        if (fPercentInMemory < 0.0)
        {
            fPercentInMemory = 0.0;
        }
        if (fPercentInMemory > 1.0)
        {
            fPercentInMemory = 1.0;
        }

        sr = new StreamReader(fileName);
        br = new BinaryReader(FileStream.Synchronized(sr.BaseStream));

        while (br.BaseStream.Position < br.BaseStream.Length)
        {
            OffsetLength offsetLength;
            int termId;

            termId = br.ReadInt32();
            offsetLength.offset = br.ReadInt32();
            offsetLength.length = br.ReadInt32();

            termId2offset.Add(termId, offsetLength);
        }

        br.Close();
        sr.Close();

        FileInfo fi = new FileInfo(dataFileName);

        byte[] abSentIdData;
        sr = new StreamReader(dataFileName);
        br = new BinaryReader(FileStream.Synchronized(sr.BaseStream));

        iDataInMemorySizeByByte = (int)(fi.Length * fPercentInMemory);
        iDataInMemorySizeByByte = iDataInMemorySizeByByte + (4 - (iDataInMemorySizeByByte % 4));
        if (iDataInMemorySizeByByte > fi.Length)
        {
            iDataInMemorySizeByByte = (int)fi.Length;
        }

        abSentIdData = br.ReadBytes(iDataInMemorySizeByByte);


        aiSentIdData = new int[abSentIdData.Length / 4];
        System.Buffer.BlockCopy(abSentIdData, 0, aiSentIdData, 0, abSentIdData.Length * sizeof(byte));

        //br.Close();
        //sr.Close();

        return true;

    }

    public int[] ReadTermSentenceIndex(int termId)
    {
        OffsetLength offsetLength;

        if (termId2offset.TryGetValue(termId, out offsetLength) == true)
        {
            int iEndOffsetByByte;
            iEndOffsetByByte = offsetLength.offset + offsetLength.length * sizeof(int);
            if (iEndOffsetByByte < iDataInMemorySizeByByte)
            {
                return ReadTermSentenceIndexInMemory(ref offsetLength);
            }
            else
            {
                return ReadTermSentenceIndexInDisk(ref offsetLength);
            }
        }
        else
        {
            return null;
        }
    }

    private int[] ReadTermSentenceIndexInDisk(ref OffsetLength offsetLength)
    {
        byte[] abData;
        int[] arrayInt;
        arrayInt = new int[offsetLength.length];
        lock (privateObject)
        {
            br.BaseStream.Seek(offsetLength.offset, SeekOrigin.Begin);
            abData = br.ReadBytes(offsetLength.length * sizeof(int));
        }
        System.Buffer.BlockCopy(abData, 0, arrayInt, 0, offsetLength.length * sizeof(int));

        return arrayInt;
    }

    private int[] ReadTermSentenceIndexInMemory(ref OffsetLength offsetLength)
    {

        int[] arrayInt;
        arrayInt = new int[offsetLength.length];
        System.Buffer.BlockCopy(aiSentIdData, offsetLength.offset, arrayInt, 0, offsetLength.length * sizeof(int));

        return arrayInt;
    }
}
